//
//  KKChartViews.swift
//  KKChartViewDemo
//
//  Created by liaozhenming on 2019/12/4.
//  Copyright © 2019 kangcun2019. All rights reserved.
//

import UIKit

class KKChartDataItem: NSObject {
    public var identifier = ""
    public var color: UIColor = UIColor.green
    public var value: Double = 0.0
    
    static func itemWith(identifier: String, color: UIColor, value: Double = 1.0)->KKChartDataItem{
        let item = KKChartDataItem.init()
        item.identifier = identifier
        item.color = color
        item.value = value
        return item
    }
}

class KKChartDataSectionItem: NSObject {
    public var color: UIColor = UIColor.orange
    public var items: [KKChartDataItem] = []
    
    static func itemWith(color: UIColor = UIColor.orange, subItems:[KKChartDataItem])->KKChartDataSectionItem{
        let sectionItem = KKChartDataSectionItem.init()
        sectionItem.color = color
        sectionItem.items = subItems
        return sectionItem
    }
}


class KKChartBaseView: UIView {
    public var arr_chartItems: [KKChartDataItem] = []
    
    //  是否动画显示
    public var isAnimation: Bool = true
    
    public func kk_updateChartViewUI(){
        self.layer.sublayers?.forEach({$0.removeFromSuperlayer()})
        self.layer.mask = nil
        //  重新绘制
        setNeedsDisplay()
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = UIColor.white
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        backgroundColor = UIColor.white
    }
    
    fileprivate func showAnimationWithShadePath(_ shadePath: UIBezierPath, lineWidth: CGFloat){
        
        let shadeLayer = CAShapeLayer.init()
        shadeLayer.fillColor = UIColor.clear.cgColor
        shadeLayer.strokeColor = UIColor.lightGray.cgColor
        shadeLayer.strokeStart = 0.0
        shadeLayer.strokeEnd = 1.0
        shadeLayer.zPosition = 1
        shadeLayer.lineWidth = lineWidth
        shadeLayer.fillRule = .nonZero
        shadeLayer.path = shadePath.cgPath
        
        self.layer.mask = shadeLayer
        
        //  设置遮罩层的动画效果
        let strokeAnimation = CABasicAnimation.init(keyPath: "strokeEnd")
        strokeAnimation.fromValue = 0
        strokeAnimation.toValue = 1
        strokeAnimation.duration = 1
        strokeAnimation.repeatCount = 1
        strokeAnimation.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut)
        strokeAnimation.isRemovedOnCompletion = true
        shadeLayer.add(strokeAnimation, forKey: "pieAnimation")
    }
    
}

//  MARK: 饼状图
class KKPieChartView: KKChartBaseView {
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        var totalValue = 0.0
        //  采用闭包的方式来统计总值
        self.arr_chartItems.forEach({totalValue += $0.value})
        
        let center = CGPoint.init(x: self.bounds.width/2.0, y: self.bounds.height/2.0)
        let radius = min(self.bounds.width, self.bounds.height) / 2.0 - 5.0
        
        var startAngle = -( Double.pi / 2.0)
        
        //  遮罩层
        let shadePath = UIBezierPath.init(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat( Double.pi / 2 * 3), clockwise: true)

        //  初始化子扇区域
        self.arr_chartItems.forEach({
            //  当前item占有的比例
            let ratio = $0.value / totalValue
            let endAngle = startAngle + ratio * .pi * 2
            
            let bezierPath = UIBezierPath.init(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: true)
            bezierPath.addLine(to: center)
            
            $0.color.setStroke()
            $0.color.setFill()
            bezierPath.stroke()
            bezierPath.fill()
            
            let shapeLayer = CAShapeLayer.init()
            shapeLayer.path = bezierPath.cgPath
            shapeLayer.strokeColor = UIColor.white.cgColor
            shapeLayer.fillColor = $0.color.cgColor
            self.layer.addSublayer(shapeLayer)
            startAngle = endAngle
        })
        
        //  动画显示
        self.showAnimationWithShadePath(shadePath, lineWidth: radius * 2)
    }
}


//  MARK: 环状图
class KKCyclicChartView: KKChartBaseView {
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        var totalValue = 0.0
        //  采用闭包的方式来统计总值
        self.arr_chartItems.forEach({totalValue += $0.value})
        
        let center = CGPoint.init(x: self.bounds.width/2.0, y: self.bounds.height/2.0)
        let radius = min(self.bounds.width, self.bounds.height) / 2.0 - 5.0
        
        var startAngle = -( Double.pi / 2.0)
        
        //  遮罩层
        let shadePath = UIBezierPath.init(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat( Double.pi / 2 * 3), clockwise: true)
        let shadeLayer = CAShapeLayer.init()
        shadeLayer.fillColor = UIColor.clear.cgColor
        shadeLayer.strokeColor = UIColor.lightGray.cgColor
        shadeLayer.strokeStart = 0.0
        shadeLayer.strokeEnd = 1.0
        shadeLayer.zPosition = 1
        shadeLayer.lineWidth = radius * 2
        shadeLayer.fillRule = .nonZero
        shadeLayer.path = shadePath.cgPath
        
        //  初始化子扇区域
        self.arr_chartItems.forEach({
            //  当前item占有的比例
            let ratio = $0.value / totalValue
            let endAngle = startAngle + ratio * .pi * 2
            
            let bezierPath = UIBezierPath.init(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: true)
            bezierPath.addLine(to: center)
            
            $0.color.setStroke()
            $0.color.setFill()
            bezierPath.stroke()
            bezierPath.fill()
            
            let shapeLayer = CAShapeLayer.init()
            shapeLayer.path = bezierPath.cgPath
            shapeLayer.strokeColor = UIColor.white.cgColor
            shapeLayer.fillColor = $0.color.cgColor
            shadeLayer.lineWidth = radius * 0.8
            self.layer.addSublayer(shapeLayer)
            startAngle = endAngle
        })
        
        self.layer.mask = shadeLayer
        
        //  设置遮罩层的动画效果
        let strokeAnimation = CABasicAnimation.init(keyPath: "strokeEnd")
        strokeAnimation.fromValue = 0
        strokeAnimation.toValue = 1
        strokeAnimation.duration = 1
        strokeAnimation.repeatCount = 1
        strokeAnimation.timingFunction = CAMediaTimingFunction.init(name: .easeInEaseOut)
        strokeAnimation.isRemovedOnCompletion = true
        shadeLayer.add(strokeAnimation, forKey: "pieAnimation")
    }
}


//  MARK: 有坐标轴的图基类
class KKAxisChartBaseView: KKChartBaseView {
    public var xAxisView: UIView = UIView.init()
    public var arr_xAxisViews: [UIView] = []
    public var xAxisSpacing: CGFloat = 20.0
    public var xAxisLineView: UIView = UIView.init()
    
    public var yAxisView: UIView = UIView.init()
    public var arr_yAxisViews: [UIView] = []
    public var yAxisSpacing: CGFloat = 20.0
    
    public var chartPannelView: UIScrollView = UIScrollView.init()
    
    public var arr_dashlineViews: [UIView] = []
    
    public var isShowYAxisLine: Bool = true
    public var columnWidth: CGFloat = 20.0
    
    public var lineColor = UIColor.init(white: 0.1, alpha: 0.5)
    public var yMaxValue: Double = 0.0
    
    public var arr_chartSectionItems: [KKChartDataSectionItem] = []
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        //  清除视图上的所有子控件
        xAxisView.subviews.forEach({$0.removeFromSuperview()})
        xAxisView.removeFromSuperview()
        yAxisView.subviews.forEach({$0.removeFromSuperview()})
        yAxisView.removeFromSuperview()
        arr_xAxisViews.forEach({$0.removeFromSuperview()})
        arr_yAxisViews.forEach({$0.removeFromSuperview()})
        chartPannelView.subviews.forEach({$0.removeFromSuperview()})
        chartPannelView.removeFromSuperview()
        //  虚线
        arr_dashlineViews.forEach({$0.removeFromSuperview()})
        
        //  X轴数据区域
        chartPannelView.frame = CGRect.init(x: 30, y: 0, width: rect.width - 30, height: rect.height)
        chartPannelView.contentSize = chartPannelView.bounds.size
        chartPannelView.showsHorizontalScrollIndicator = false
        chartPannelView.showsVerticalScrollIndicator = false
        addSubview(chartPannelView)
        
        //  x轴设置
        self.xAxisLineView.backgroundColor = lineColor
        chartPannelView.addSubview(self.xAxisLineView)
        
        //  Y轴设置
        yAxisView.frame = CGRect.init(x: 0, y: 0, width: 30, height: rect.height - 30)
        addSubview(yAxisView)
        let yLineView = UIView.init(frame: CGRect.init(x: yAxisView.bounds.width - 1, y: 0, width: 1, height: yAxisView.bounds.height))
        yLineView.backgroundColor = lineColor
        yAxisView.addSubview(yLineView)
        
        let maxHeight = yAxisView.bounds.height - 10
        yAxisSpacing = maxHeight / 5.0
        
        self.yMaxValue = self.private_getMaxYAxisValue()
        
        //  Y轴间隔值
        let yAxisSpaceValue = self.yMaxValue / 5.0
        
        //  绘制Y轴上显示的数字
        for index in 1...5{
            let pointY = maxHeight + 10 - CGFloat(index) * yAxisSpacing
            
            let lab_yAxisNum = UILabel.init(frame: CGRect.init(x: 0, y: pointY - 8, width: 29, height: 16))
            lab_yAxisNum.font = UIFont.systemFont(ofSize: 8)
            lab_yAxisNum.textAlignment = .center
            lab_yAxisNum.textColor = UIColor.init(white: 0.1, alpha: 0.5)
            lab_yAxisNum.text = "\(yAxisSpaceValue * Double(index))"
            yAxisView.addSubview(lab_yAxisNum)
            
            //  显示Y轴虚线.
            if self.isShowYAxisLine {
                let dashlineView = UIView.init(frame: CGRect.init(x: 0, y: pointY, width: chartPannelView.contentSize.width, height: 1))
                chartPannelView.addSubview(dashlineView)
                arr_dashlineViews.append(dashlineView)
            }
        }
    }
    //  获取Y轴上的最大值
    private func private_getMaxYAxisValue()->Double{
        
        var maxValue = 0.0
        
        if self.arr_chartSectionItems.count > 0 {
            self.arr_chartSectionItems.forEach({
                $0.items.forEach({maxValue = maxValue < $0.value ? $0.value : maxValue})
            })
        }
        else {
            self.arr_chartItems.forEach({maxValue = maxValue < $0.value ? $0.value : maxValue})
        }
        return ceil(maxValue)
    }
    //  更新X轴区域上控件的宽度
    fileprivate func updateChartPannelViewsUI(pannelWidth: CGFloat){
        self.chartPannelView.contentSize = CGSize.init(width: pannelWidth, height: self.chartPannelView.bounds.height)
        
        //  重新布局y轴虚线
        self.arr_dashlineViews.forEach({
            $0.frame = CGRect.init(x: $0.frame.minX, y: $0.frame.minY, width: pannelWidth, height: $0.bounds.height)
            
            let lineLayer = CAShapeLayer.init()
            lineLayer.bounds = $0.bounds
            lineLayer.position = CGPoint.init(x: $0.bounds.width / 2, y: $0.bounds.height / 2)
            lineLayer.lineWidth = 0.5
            lineLayer.lineDashPattern = [NSNumber.init(value: 2),NSNumber.init(value: 1)]
            lineLayer.strokeColor = UIColor.init(white: 0.3, alpha: 0.7).cgColor
            
            let path = CGMutablePath.init()
            path.move(to: CGPoint.init(x: 0, y: 0))
            path.addLine(to: CGPoint.init(x: $0.bounds.width, y: 0))
            lineLayer.path = path
            $0.layer.addSublayer(lineLayer)
        })
        //  重新布局x轴线的宽度
        self.xAxisLineView.frame = CGRect.init(x: 0, y: self.chartPannelView.bounds.height - 30, width: pannelWidth, height: 1)
        
        //  动画显示
        let shadePath = UIBezierPath.init()
        shadePath.move(to: CGPoint.init(x: pannelWidth / 2.0, y: self.chartPannelView.bounds.height))
        shadePath.addLine(to: CGPoint.init(x: pannelWidth / 2.0, y: 0))
        shadePath.lineWidth = pannelWidth
        self.showAnimationWithShadePath(shadePath, lineWidth: pannelWidth)
    }
}

//  MARK: 柱状图
class KKBarChartView: KKAxisChartBaseView{
    
    public var isColumnGradationColor: Bool = false
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        //  绘制数据
        var pointX: CGFloat = 10.0
        var itemWidth: CGFloat = 50.0
        let totalHeight = self.chartPannelView.bounds.height - 40
        if self.arr_chartSectionItems.count > 0 {
            //  多维数据
            
            itemWidth = 30.0
            
            self.arr_chartSectionItems.forEach({
                
                $0.items.forEach({
                    let heightRatio = $0.value / self.yMaxValue
                    
                    let itemHeight = totalHeight * CGFloat(heightRatio)
                    let pointY = totalHeight * CGFloat(1.0 - heightRatio)
                    
                    let itemView = UIView.init(frame: CGRect.init(x: pointX, y: pointY + 10, width: itemWidth, height: itemHeight))
                    self.chartPannelView.addSubview(itemView)
                    
                    if (self.isColumnGradationColor){
                        let columnGradientLayer = CAGradientLayer.init()
                        columnGradientLayer.frame = itemView.bounds
                        columnGradientLayer.colors = [UIColor.lightGray.cgColor,UIColor.yellow.cgColor]
                        columnGradientLayer.locations = [NSNumber.init(value: 0.0),NSNumber.init(value: 1.0)]
                        columnGradientLayer.startPoint = CGPoint.zero
                        columnGradientLayer.endPoint = CGPoint.init(x: 0.0, y: 1.0)
                        itemView.layer.addSublayer(columnGradientLayer)
                    }
                    else {
                        let columnPath = UIBezierPath.init()
                        columnPath.move(to: CGPoint.init(x: itemView.bounds.width/2.0, y: itemView.bounds.height))
                        columnPath.addLine(to: CGPoint.init(x: itemView.bounds.width/2.0, y: 0))
                        let columnLayer = CAShapeLayer.init()
                        columnLayer.path = columnPath.cgPath
                        columnLayer.strokeColor = UIColor.yellow.cgColor
                        columnLayer.fillColor = UIColor.yellow.cgColor
                        columnLayer.lineWidth = itemWidth
                        itemView.layer.addSublayer(columnLayer)
                    }
                    pointX += (itemWidth + 5.0)
                })
                
                pointX += 30.0
            })
        }
        else {
            //  单维数据
            self.arr_chartItems.forEach({
                let heightRatio = $0.value / self.yMaxValue
                let totalHeight = self.chartPannelView.bounds.height - 40
                let itemHeight = totalHeight * CGFloat(heightRatio)
                let pointY = totalHeight * CGFloat(1.0 - heightRatio)
                
                let itemView = UIView.init(frame: CGRect.init(x: pointX, y: pointY + 10, width: itemWidth, height: itemHeight))
                self.chartPannelView.addSubview(itemView)
                
                if (self.isColumnGradationColor){
                    let columnGradientLayer = CAGradientLayer.init()
                    columnGradientLayer.frame = itemView.bounds
                    columnGradientLayer.colors = [UIColor.lightGray.cgColor,UIColor.yellow.cgColor]
                    columnGradientLayer.locations = [NSNumber.init(value: 0.0),NSNumber.init(value: 1.0)]
                    columnGradientLayer.startPoint = CGPoint.zero
                    columnGradientLayer.endPoint = CGPoint.init(x: 0.0, y: 1.0)
                    itemView.layer.addSublayer(columnGradientLayer)
                }
                else {
                    let columnPath = UIBezierPath.init()
                    columnPath.move(to: CGPoint.init(x: itemView.bounds.width/2.0, y: itemView.bounds.height))
                    columnPath.addLine(to: CGPoint.init(x: itemView.bounds.width/2.0, y: 0))
                    let columnLayer = CAShapeLayer.init()
                    columnLayer.path = columnPath.cgPath
                    columnLayer.strokeColor = UIColor.yellow.cgColor
                    columnLayer.fillColor = UIColor.yellow.cgColor
                    columnLayer.lineWidth = itemWidth
                    itemView.layer.addSublayer(columnLayer)
                }
                
                pointX += 60.0
            })
        }

        self.updateChartPannelViewsUI(pannelWidth: pointX)
    }
}


//  MARK: 折线图
class KKLineChartView: KKAxisChartBaseView{
    
    var isShowPoint: Bool = false
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        //  绘制数据
        var pointX: CGFloat = 10.0
        let totalHeight = self.chartPannelView.bounds.height - 40
        var itemSpace: CGFloat = 50.0
        
        if self.arr_chartSectionItems.count > 0 {
            //  多维数据
            
            var itemCount = 0
            self.arr_chartSectionItems.forEach({
                itemCount = $0.items.count > itemCount ? $0.items.count : itemCount
            })
            
            let tmpItemSpace = self.chartPannelView.bounds.width / CGFloat(itemCount)
            
            itemSpace = tmpItemSpace > 50.0 ? tmpItemSpace : 50.0
            
            self.arr_chartSectionItems.forEach({
                pointX = 10.0
                let linePath = UIBezierPath.init()
                for(index,tmpItem) in $0.items.enumerated() {
                    
                    let heightRatio = tmpItem.value / self.yMaxValue
                    let pointY = totalHeight * CGFloat(1.0 - heightRatio) + 10
                    
                    if index == 0 {
                        linePath.move(to: CGPoint.init(x: pointX, y: pointY))
                    }
                    else {
                        linePath.addLine(to: CGPoint.init(x: pointX, y: pointY))
                    }
                    pointX += itemSpace
                }
                linePath.lineCapStyle = .butt
                
                let lineLayer = CAShapeLayer.init()
                lineLayer.path = linePath.cgPath
                lineLayer.lineWidth = 1
                lineLayer.strokeColor = $0.color.cgColor
                lineLayer.fillColor = nil
                self.chartPannelView.layer.addSublayer(lineLayer)
            })
        }
        else {
            //  单维数据
            let tmpItemSpace = self.chartPannelView.bounds.width / CGFloat(self.arr_chartItems.count)
            itemSpace = tmpItemSpace > 50.0 ? tmpItemSpace : 50.0
            
            let linePath = UIBezierPath.init()
            for(index,tmpItem) in self.arr_chartItems.enumerated() {
                
                let heightRatio = tmpItem.value / self.yMaxValue
                let pointY = totalHeight * CGFloat(1.0 - heightRatio) + 10
                
                if index == 0 {
                    linePath.move(to: CGPoint.init(x: pointX, y: pointY))
                }
                else {
                    linePath.addLine(to: CGPoint.init(x: pointX, y: pointY))
                }
                
                do{
                    //  绘制圆点
                    let center = CGPoint.init(x: pointX, y: pointY)
                    let bezierPath = UIBezierPath.init(arcCenter: center, radius: 3.0, startAngle: CGFloat(-( Double.pi / 2.0)), endAngle: CGFloat(Double.pi / 2 * 3), clockwise: true)
                    
                    let shapeLayer = CAShapeLayer.init()
                    shapeLayer.path = bezierPath.cgPath
                    shapeLayer.strokeColor = UIColor.blue.cgColor
                    shapeLayer.fillColor = UIColor.red.cgColor
                    self.chartPannelView.layer.addSublayer(shapeLayer)
                }
                
                pointX += itemSpace
            }
            linePath.lineCapStyle = .butt
            
            let lineLayer = CAShapeLayer.init()
            lineLayer.path = linePath.cgPath
            lineLayer.lineWidth = 1
            lineLayer.strokeColor = UIColor.green.cgColor
            lineLayer.fillColor = nil
//            self.chartPannelView.layer.addSublayer(lineLayer)
            self.chartPannelView.layer.insertSublayer(lineLayer, at: 0)
        }
        
        self.updateChartPannelViewsUI(pannelWidth: pointX)
    }
}
